#pragma once
#include <iostream>

static inline void *&NextObj(void *obj)
{
    // 返回值加引用的原因是：返回值不加引用的话，是返回的一个临时拷贝，具有常属性，不能被修改。
    // 会导致NextObj(obj) = xxx; 无法执行，所以要带引用返回
    return *(void **)obj;
}

template<class T>
class FLPool
{
public:
    //申请内存
    T* New()
    {
        //先在自由链表中找
        if(_freelist != nullptr)
        {
            void* obj = _freelist;
            _freelist = NextObj(obj);
            NextObj(obj) = nullptr;
            return obj;
        }
        //在大块内存中切割
        else
        {
            //没有了，向系统申请
            if(_remainbyte < sizeof(T))
            {
                _remainbyte = 128 * 1024;
                _memory = (char*)SystemAlloc(_remainbyte >> PAGE_SHIFT);
                if(_memory == nullptr)
                    std::bad_alloc();
            }
            //切割
            T* obj = (T*)_memory;
            //如果小于一个指针的大小，则给一个指针大小的内存块
            size_t objSize = sizeof(T) < sizeof(void*) ? sizeof(void*) : sizeof(T);
            _memory += objSize;
            _remainbyte -= sizeof(T);
            NextObj(obj) = nullptr;

            new(obj)T;
            return obj;
        }
    }
    //释放内存
    void Delete(T* obj)
    {
        assert(obj);

        obj->~T();
        NextObj(obj) = _freelist;
        _freelist = obj;
    }
private:
    char* _memory;      //申请下来的大块内存
    void* _freelist;    //自由链表
    size_t _remainbyte; //大块内存剩余情况
};